/**
  * @file 		device.c
  * @brief		系统设备层，主要描述虚拟设备数据的读写、中断的处理等逻辑。
  *
  * @copyright  Copyright (c) 2020~2030 ShenZhen Dxtc Technology Co., Ltd. 
  * All rights reserved.
  *
  * @version	v3.1
  * @author		FengLi
  * @date 		2021-08-02
  *
  * @note		鼎新同创·智能锁
  * 
  * @par 修改日志:
  * <1> 2021/08/02 v3.1 FengLi 创建初始版本
  *******************************************************************/
#include "device.h"
#include "string.h"

/** @brief   硬件设备回调结构类型 */
typedef struct DeviceCallback
{
    struct DeviceCallback *next;             ///< 链表指针，指向下一个节点
    VirtualHardware_enum_t dev;              ///< 注册调的设备
    FunctionalState status;                  ///< 回调的状态（使能/禁能）
    void (*fn_cb)(VirtualHardware_enum_t dev, void *data, uint32_t len); ///< 回调函数指针
}DeviceCallback_stu_t;
 

/** @brief   设备控制块列表  */
__EFRAM static Device_stu_t device_ctrl_block[(uint32_t)vDEVICE_QTY];

/** @brief   设备回调表  */
static DeviceCallback_stu_t *device_cb_list[(uint32_t)vDEVICE_QTY];
static uint32_t device_init_flag;  ///< 设备初始化标志

/** @brief   中断源  */
static volatile VirtualHardware_enum_t irq_device;

/** @brief   临界区嵌套计数  */
static volatile uint32_t caitical_count = 0;


//! /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
  * @brief  设备自动初始化接口开始位置
  * @details 详细说明：只是提供一个函数地址，无意义
  *         
  * @return NULL
  */
static void Device_Init_Start(void)
{
    return;
}

/**
  * @brief  设备自动初始化接口结束位置
  * @details 详细说明：只是提供一个函数地址，无意义
  *         
  * @return NULL
  */
static void Device_Init_End(void)
{
    return;
}

/** @brief   挂载设备自动初始化入口（首端）函数 */
DEVICE_START_EXPORT(Device_Init_Start);

/** @brief   挂载设备自动初始化出口（末端）函数 */
DEVICE_END_EXPORT(Device_Init_End);
//! /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
  * @brief  输入端口扫描
  * @details 详细说明：该函数在定时器中断里面周期调用，实现端口消抖、状态检测
  *         
  * @return  NULL
  */
__attribute__((weak)) void InputPort_Scan(uint8_t mask, uint16_t interval)
{

}

/**
  * @brief  检查特殊IO，有状态变化就返回对应的PIN
  * @details 详细说明：休眠状态下，设备层会调用该函数
  * @return  vNOHARDWARE：虚拟设备类型-无设备
  */
__attribute__((weak)) uint32_t InputPort_CheckSpecialGpio(void)
{
	return vNOHARDWARE;
}

/**
  * @brief  设备层滴答中断
  * @details 详细说明:1ms中断一次，扫input_port
  *         
  * @param[in]  p：无意义（兼容注册回调的函数，不可删去）
  * @param[in]  len：无意义
  *         
  * @return NULL
  */
static void Device_SysTickHandler(VirtualHardware_enum_t dev, void *p, uint32_t len)
{
    /* 调用OSAL中断接口，提供滴答节拍 */
    OSAL_SysTickHandler();

    /* 调用扫描input port */
    InputPort_Scan(0xFF, 1);
}

/**
  * @brief  获取硬件中断源
  * @details 详细说明:无
  *         
  * @return  中断源
  */
static inline uint32_t Device_GetIntSource(void)
{
    /* 获取硬件中断源 */
    Device_EnterCritical();
    uint32_t irq = irq_device;
    irq_device = vNOHARDWARE;
    Device_ExitCritical();
    if (irq != vNOHARDWARE)
    {
        return irq;
    }

    /* 获取特殊中断源：检查特殊IO是否有状态变化 */
    return InputPort_CheckSpecialGpio();
}

/**
  * @brief  获取虚拟设备的设备类型
  * @details 详细说明:无
  *         
  * @param[in]  dev：虚拟设备
  *         
  * @return  虚拟设备的类型
  */
inline static DeviceType_enum_t Device_GetDevType(VirtualHardware_enum_t dev)
{
    DeviceType_enum_t devtype = (DeviceType_enum_t)(dev >> 8);
    if(devtype < vDEVICE_QTY)
    {
        return devtype;
    }
    else
    {
        return vDEVICE_QTY;
    }
}

/**
  * @brief  打开虚拟设备
  * @details 详细说明:无
  *         
  * @param[in]  dev：虚拟设备
  *         
  * @return 失败返回-1。成功返回0
  */
int8_t Device_Enable(VirtualHardware_enum_t dev)
{
    DeviceType_enum_t deviceType = Device_GetDevType(dev);
    if(deviceType < vDEVICE_QTY && device_ctrl_block[deviceType].enable != NULL)
    {
        return device_ctrl_block[deviceType].enable(dev);
    }
    return -1;
}

/**
  * @brief  关闭虚拟设备
  * @details 详细说明:无
  *         
  * @param[in]  dev：虚拟设备
  *         
  * @return 失败返回-1。成功返回0
  */
int8_t Device_Disable(VirtualHardware_enum_t dev)
{
    DeviceType_enum_t deviceType = Device_GetDevType(dev);
    if(deviceType < vDEVICE_QTY && device_ctrl_block[deviceType].disable != NULL)
    {
        device_ctrl_block[deviceType].disable(dev);
    }
    return -1;
}

/**
  * @brief  从虚拟设备中读取数据
  * @details 详细说明:无
  *         
  * @param[in]  dev：虚拟设备
  * @param[in]  data：读取数据保存的位置
  * @param[in]  len：读取的字节数
  * @param[in]  param：不同虚拟设备表示不同的涵义，如在eeprom中该参数表示需要读取的地址值
  *         
  * @return 失败返回-1。成功返回0
  */
int32_t Device_Read(VirtualHardware_enum_t dev, void *data, uint32_t len, uint32_t param)
{
    DeviceType_enum_t deviceType = Device_GetDevType(dev);
    if(deviceType < vDEVICE_QTY && device_ctrl_block[deviceType].read != NULL)
    {
        return device_ctrl_block[deviceType].read(dev, data, len, param);
    }
    return -1;    
}

/**
  * @brief  把数据写入到虚拟设备中
  * @details 详细说明:无
  *         
  * @param[in]  dev：虚拟设备
  * @param[in]  data：需要写入的数据
  * @param[in]  len：写入数据的字节数
  * @param[in]  param：不同虚拟设备表示不同的涵义，如在eeprom中该参数表示写入的地址值
  *         
  * @return 失败返回-1。成功返回0
  */
int32_t Device_Write(VirtualHardware_enum_t dev, void *data, uint32_t len, uint32_t param)
{
    DeviceType_enum_t deviceType = Device_GetDevType(dev);
    if(deviceType < vDEVICE_QTY && device_ctrl_block[deviceType].write != NULL)
    {
        return device_ctrl_block[deviceType].write(dev, data, len, param);
    }
    return -1;
}

/**
  * @brief  设置串口波特率
  * @details 详细说明:仅限虚拟串口设备才有效
  *         
  * @param[in]  dev：虚拟设备
  * @param[in]  baudrate：需要设备的波特率
  *         
  * @return 失败返回-1。成功返回0
  */
int8_t Device_SetUartBaudrate(VirtualHardware_enum_t dev, uint32_t baudrate)
{
    DeviceType_enum_t deviceType = Device_GetDevType(dev);
    if(deviceType != vUART)//< 非串口设备不能设置串口波特率
    {
        return -1;
    }
    else
    {
        if(device_ctrl_block[deviceType].set_uart_baudrate != NULL)
        {
            return device_ctrl_block[deviceType].set_uart_baudrate(dev, baudrate);
        }
    }
    return -1;
}

/**
  * @brief  设置PWM参数
  * @details 详细说明:仅限PWM设备才有效
  *         
  * @param[in]  dev：虚拟设备
  * @param[in]  frequency：pwm频率（单位：HZ）
  * @param[in]  duty_cycle：pwm占空比（范围：0.00 ~ 100.00）
  *         
  * @return 失败返回-1。成功返回0
  */
int8_t Device_SetPwm(VirtualHardware_enum_t dev, uint32_t frequency, float duty_cycle)
{
    DeviceType_enum_t deviceType = Device_GetDevType(dev);
    if(deviceType != vPWM)//< 非PWM设备不能设置PWM参数
    {
        return -1;
    }
    else
    {
        if(device_ctrl_block[deviceType].set_pwm != NULL)
        {
            return device_ctrl_block[deviceType].set_pwm(dev, frequency, duty_cycle);
        }
    }
    return -1;
}

/**
  * @brief  加解密接口
  * @details 详细说明:仅限Crypto设备才有效
  *         
  * @param[in]  param：加解密参数，具体参考Crypto_enum_t枚举
  * @param[in]  src：源
  * @param[in]  len：源的字节数
  * @param[in]  dst：目的地
  * @param[in]  key：密钥
  *         
  * @return 失败返回-1。成功返回0
  */
int8_t Device_Crypto(Crypto_enum_t param, void *src, uint32_t len, void *dst, void *key)
{
    if(device_ctrl_block[vCRYPTO].crypto != NULL)
    {
        return device_ctrl_block[vCRYPTO].crypto(param, src, len, dst, key);
    }
    else
    {
        return -1;
    }
}

/**
  * @brief  注册硬件中断回调（给组件层调用的接口）
  * @details 详细说明:无
  *         
  * @param[in]  dev：虚拟设备
  * @param[in]  cb：回调函数
  *         
  * @return 失败返回-1。成功返回0
  */
int8_t Device_RegisteredCB(VirtualHardware_enum_t dev, void (*cb)(VirtualHardware_enum_t, void *, uint32_t))
{
    DeviceType_enum_t deviceType = Device_GetDevType(dev);

    if(cb == NULL || deviceType >= vDEVICE_QTY)
    {
        return -1;
    }

    if (device_cb_list[deviceType] == NULL)
    {
        DeviceCallback_stu_t *tmp = (DeviceCallback_stu_t *)OSAL_Malloc(sizeof(DeviceCallback_stu_t));
        if (tmp != NULL)
        {
            tmp->status = ENABLE;
            tmp->dev = dev;
            tmp->fn_cb = cb;
            tmp->next = NULL;
            
            Device_EnterCritical();
            device_cb_list[deviceType] = tmp;
            Device_ExitCritical();
            return 0;
        }
    }
    else
    {
        DeviceCallback_stu_t *pCb_list = device_cb_list[deviceType];

        for (;;)
        {
            if (pCb_list->dev == dev)
            {
                Device_EnterCritical();
                pCb_list->fn_cb = cb;
                pCb_list->status = ENABLE;
                Device_ExitCritical();
                return 0;
            }

            if (pCb_list->next != NULL)
            {
                pCb_list = pCb_list->next;
            }
            else
            {
                break;
            }
        }

        DeviceCallback_stu_t *tmp = (DeviceCallback_stu_t *)OSAL_Malloc(sizeof(DeviceCallback_stu_t));
        if (tmp != NULL)
        {
            tmp->status = ENABLE;
            tmp->dev = dev;
            tmp->fn_cb = cb;
            tmp->next = NULL;

            Device_EnterCritical();
            pCb_list->next = tmp;
            Device_ExitCritical();
            return 0;
        }
    }
    return -1;
}

/**
  * @brief  设置中断回调函数执行的状态（或开关）
  * @details 详细说明:无
  *         
  * @param[in]  dev：虚拟设备
  * @param[in]  status: 中断回调函数的开关（使能、禁能）
  *         
  * @return 失败返回-1。成功返回0
  */
int8_t Device_ConfigCB(VirtualHardware_enum_t dev, FunctionalState status)
{
    DeviceType_enum_t deviceType = Device_GetDevType(dev);
    DeviceCallback_stu_t *pCb_list = device_cb_list[deviceType];

    if (deviceType >= vDEVICE_QTY)
    {
        return -1;
    }

    for (; pCb_list != NULL; pCb_list = pCb_list->next)
    {
        if (pCb_list->dev == dev)
        {
            pCb_list->status = status;
            return 0;
        }
    }
    return -1;
}

/**
  * @brief  中断服务函数
  * @details 详细说明:给底层驱动调用的接口
  *         
  * @param[in]  dev：虚拟设备
  * @param[in]  data: 中断需要处理的数据
  * @param[in]  len: 需要处理数据的长度
  *         
  * @return NULL
  */
void Device_IRQHandler(VirtualHardware_enum_t dev, void *data, uint32_t len)
{
    DeviceType_enum_t deviceType = Device_GetDevType(dev);

    if (deviceType >= vDEVICE_QTY)
    {
        return;
    }

    /* 记录中断源（休眠唤醒逻辑会用到） */
    if (deviceType == vPIN     ||
        deviceType == vIPC     ||
        deviceType == vBLE     ||
        deviceType == vWIFI    ||
        deviceType == vNETWORK ||
        deviceType == vCOUNTER ||
        deviceType == vRTC     ||
        dev == vTIMER_1)
    {
        Device_EnterCritical();
        irq_device = (irq_device == vNOHARDWARE || irq_device == vTIMER_1) ? dev : irq_device;
        Device_ExitCritical();
    }

    if (device_init_flag != UINT32_FLAG)
    {
        return;
    }

    /* 执行硬件中断回调 */
    for (DeviceCallback_stu_t *pCb_list = device_cb_list[deviceType]; pCb_list != NULL; pCb_list = pCb_list->next)
    {
        if (pCb_list->dev == dev && pCb_list->status == ENABLE)
        {
            pCb_list->fn_cb(dev, data, len);
            break;
        }
    }
}

/**
  * @brief  获取设备控制块
  * @details 详细说明:无
  *         
  * @param[in]  dev_type：底层硬件设备类型
  *         
  * @return 设备控制块
  */
Device_stu_t *Device_GetDeviceCtrlBlock(DeviceType_enum_t dev_type)
{
    if (dev_type < vDEVICE_QTY)
    {
        return &device_ctrl_block[dev_type];
    }
    else
    {
        return NULL;
    }
}

/**
  * @brief  设备初始化
  * @details 详细说明:无
  *         
  * @return NULL
  */
void Device_Init(void)
{
	const Device_Init_fn_t *fn_ptr = &__Hwl_Init_Device_Init_Start;

    __OSAL_LOG("[device.c] Device_Init\r\n");

	fn_ptr++;
    for (; fn_ptr < &__Hwl_Init_Device_Init_End; fn_ptr++)
    {
        (*fn_ptr)();
    }

    //< 注册定时器回调
    Device_RegisteredCB(vTIMER_0, Device_SysTickHandler);

    device_init_flag = UINT32_FLAG;
}

/**
  * @brief  配置设备深度睡眠
  * @details 详细说明:无
  *         
  * @param[in]  time：设备进入睡眠的时间
  *         
  * @return 硬件中断源
  */
uint32_t Device_DeepSleep(uint32_t time)
{
    /* 休眠前喂一次狗 */
    // Device_FeedDog();

    /* 休眠前获取中断源 */
    uint32_t irq = Device_GetIntSource();
    if (irq != 0xFFFF)
    {
        return irq;
    }

    /* CPU深度睡眠 */
    if (time > 0)
    {
        Device_CpuSleep(time);
    }

    /* 唤醒后立即获取中断源 */
    return Device_GetIntSource();
}

/**
  * @brief  将中断源设置为空
  * @details 详细说明:无
  *         
  * @return NULL
  */
void Device_ClearInterrupt(void)
{
    irq_device = vNOHARDWARE;
}

/**
  * @brief  开总中断
  * @details 详细说明:无
  *         
  * @return NULL
  */
__attribute__((weak)) void Device_EnableIRQ(void)
{
    ;
}

/**
  * @brief  关总中断
  * @details 详细说明:无
  *         
  * @return NULL
  */
__attribute__((weak)) void Device_DisableIRQ(void)
{
    ;
}

/**
  * @brief  进入临界区
  * @details 详细说明:无
  *         
  * @return NULL
  */
void Device_EnterCritical(void)
{
    if (caitical_count == 0 || device_init_flag != UINT32_FLAG)
    {
        Device_DisableIRQ();
    }
    caitical_count++;
}

/**
  * @brief  退出临界区
  * @details 详细说明:无
  *         
  * @return NULL
  */
void Device_ExitCritical(void)
{
    caitical_count--;
    if (caitical_count == 0 || device_init_flag != UINT32_FLAG)
    {
        Device_EnableIRQ();
    }
}
